#include "Channel_server.hpp"
#include "Socket_server.hpp"
#include "Buffer_server.hpp"
#include"Any_server.hpp"
#include <memory>


class Connection;

// 当前连接的状态，连接关闭； 连接建议成功待处理； 连接成功，各种设置已经完成，可以通信； 待关闭；
typedef enum
{
    DISCONNECTED,
    CONNECTING,
    CONNECTED,
    DISCONNECTING
} ConnStatu;

using PtrConnection = std::shared_ptr<Connection>;

class Connection : public std::enable_shared_from_this<Connection>
{
private:
    uint64_t _conn_id;             // 唯一的连接ID
    int _sockfd;                   // 连接关联的的文件描述符
    bool _enable_inactive_release; // 连接的文件描述符是否启动非活跃销毁的判断标志，默认为false;

    Any _context;

    EventLoop *_loop;
    ConnStatu _statu;
    Socket _socket;
    Channel _channel;
    Buffer _in_buffer;
    Buffer _out_buffer;

    using ConnectionCallback = std::function<void(const PtrConnection &)>;
    using MessageCallback = std::function<void(const PtrConnection &, Buffer *)>;
    using ClosedCallback = std::function<void(const PtrConnection &)>;
    using AnyEventCallback = std::function<void(const PtrConnection &)>;

    ConnectionCallback _connected_callback;
    MessageCallback _message_callback;
    ClosedCallback _closed_callback;
    AnyEventCallback _anyevent_callback;
    ClosedCallback _server_closed_callback;

private:
    void HandleRead()
    {
        char buf[65536];

        ssize_t ret = _socket.NonBlockRecv(buf, 65535);

        if (ret < 0)
        {
            return ShutdoenInLoop();
        }


        _in_buffer.WriteAndPush(buf, ret);

        if (_in_buffer.ReadAbleSize() > 0)
        {
            return _message_callback(shared_from_this(), &_in_buffer);
        }
    }

    void HandleWrite()
    {
        ssize_t ret = _socket.NonBlockSend(_out_buffer.ReaderPosition(), _out_buffer.ReadAbleSize());
        if (ret < 0)
        {
            if (_in_buffer.ReadAbleSize() > 0)
            {
                _message_callback(shared_from_this(), &_in_buffer);
            }
            return Release();
        }
        _out_buffer.MoveReadOffset(ret);

        if (_out_buffer.ReadAbleSize() == 0)
        {
            _channel.DisableWrite();

            if (_statu == DISCONNECTING)
            {
                return Release();
            }
        }
        return;
    }

    void HandleClose()
    {
        if(_in_buffer.ReadAbleSize()>0)
        {
            _message_callback(shared_from_this(),&_in_buffer);

        }
        return Release();
    }

    void HandleError()
    {
        return HandleClose();
    }

    void HandleEvent()
    {
        if(_enable_inactive_release==true)
        {
            _loop->TimerRefresh(_conn_id);
        }

       if(_anyevent_callback)
       {
        _anyevent_callback(shared_from_this());
       }
    }

    void EstablishedInLoop()
    {
        assert(_statu==CONNECTING);
        _statu=CONNECTED;

        _channel.EanbleRead();

        if(_connected_callback) _connected_callback(shared_from_this());
    }


    void ReleaseInLoop()
    {
        _statu=DISCONNECTED;

        _channel.Remove();

        _socket.Close();

        if(_loop->HasTimer(_conn_id))ChacnelInactiveReleaseInLoop();

        if(_closed_callback) _closed_callback(shared_from_this());

        if(_server_closed_callback)
        {
            _server_closed_callback(shared_from_this());
        }
    }

    void SendInLoop(Buffer &buf)
    {
        if(_statu==DISCONNECTED)return;

        _out_buffer.WriteBufferAndPush(buf);

        if(_channel.WriteAble()==false)
        {
            _channel.EanbleWrite();
        }
    }


    void ShutdoenInLoop()
    {
        _statu=DISCONNECTING;

        if(_in_buffer.ReadAbleSize()>0)
        {
            if(_message_callback) _message_callback(shared_from_this(),&_in_buffer);
        }

        if(_out_buffer.ReadAbleSize()>0)
        {
            if(_channel.WriteAble()==false)
            {
                _channel.EanbleWrite();
            }
        }

        if(_out_buffer.ReadAbleSize()==0)
        {
            Release();
        }

    }


    void EanbleInactiveReleaseInLoop(int sec)
    {
        _enable_inactive_release=true;

        if(_loop->HasTimer(_conn_id))
        {
            return _loop->TimerRefresh(_conn_id);
        }

        _loop->TimerAdd(_conn_id,sec,std::bind(&Connection::Release,this));

    }

    void ChacnelInactiveReleaseInLoop()
    {
        _enable_inactive_release=false;

        if(_loop->HasTimer(_conn_id))
        {
            _loop->TimerCancel(_conn_id);
        }
    }

    void UpgradeInLoop(const Any &context,const ConnectionCallback &conn,const MessageCallback &msg,
                       const ClosedCallback &closed, const AnyEventCallback &event)
    {
        _context=context;
        _connected_callback=conn;
        _message_callback=msg;
        _closed_callback=closed;
        _anyevent_callback=event;
    }


    public:

    Connection(EventLoop* loop,uint64_t conn_id,int sockfd):_conn_id(conn_id),_sockfd(sockfd),
    _enable_inactive_release(false),_loop(loop),_statu(CONNECTING),_socket(_sockfd),_channel(loop,_sockfd)
    {
        _channel.SetCloseCallback(std::bind(&Connection::HandleClose,this));
        _channel.SetEventCallback(std::bind(&Connection::HandleEvent,this));
        _channel.SetErrorCallback(std::bind(&Connection::HandleError,this));
        _channel.SetReadCallback(std::bind(&Connection::HandleRead,this));
        _channel.SetWriteCallback(std::bind(&Connection::HandleWrite,this));
    }

    ~Connection(){DBG_LOG("RELEASE CONNECTION: %p",this)};

    int Fd()
    {
        return _sockfd;
    }

    int Id()
    {
        return _conn_id;
    }

    bool SetContext(const Any &context)
    {
        _context=context;

        return true;
    }
    
    Any* GetContext()
    {
        return &_context;
    }

    void SetConnectedCallback(const ConnectionCallback &cb)
    {
        _connected_callback=cb;
    }

    void SetMessageCallback(const MessageCallback &cb)
    {
        _message_callback=cb;
    }

    void SetClosedCallback(const ClosedCallback &cb)
    {
        _closed_callback=cb;
    }

    void SetAnyEventCallback(const AnyEventCallback &cb)
    {
        _anyevent_callback=cb;
    }

    void SetSrvClosedCallback(const ClosedCallback &cb)
    {
        _server_closed_callback=cb;
    }

    void Established()
    {
        _loop->RunInLoop(std::bind(&Connection::EstablishedInLoop,this));
    }

    void Send(const char* data,size_t len)
    {
        Buffer buf;
        buf.WriteAndPush(data,len);
        _loop->RunInLoop(std::bind(&Connection::SendInLoop,this,std::move(buf)));

    }

    void Shutdown()
    {
        _loop->RunInLoop(std::bind(&Connection::ShutdoenInLoop,this));
    }

    void Release()
    {
        _loop->QueueInLoop(std::bind(&Connection::ReleaseInLoop,this));
    }

    void CancelInactiveRelease()
    {
        _loop->RunInLoop(std::bind(&Connection::ChacnelInactiveReleaseInLoop,this));
    }

    void Upgeade(const Any & context,const ConnectionCallback &conn,const MessageCallback &msg,
        const ClosedCallback &closed,const AnyEventCallback &event)
        {
            _loop->AssertInLoop();
            _loop->RunInLoop(std::bind(&Connection::UpgradeInLoop,this,context,conn,msg,closed,event));

        }


};